package com.zz.utils;

import com.alibaba.fastjson.JSONObject;
import com.zz.common.*;
import com.zz.constants.EsignRequestType;
import com.zz.exception.EsignDemoException;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;

import java.io.FileInputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.util.LinkedHashMap;

@Slf4j
@UtilityClass
public class ESignApiUtil {

    RestTemplate client = new RestTemplate();


    // 查询个人签署账号（通过accountId查询）
    public static JSONObject getAccountByAccountId(ESignParameter parameter, String type, String accountId) {
        String accountsApi = "/v1/accounts/" + accountId;
        return sendGet(parameter, type, accountsApi);
    }


    // 通过身份证号验证账号是否存在
    public static JSONObject checkAccountById(ESignParameter parameter, String type, String idNum) {
        String accountsApi = "/v1/accounts/getByThirdId?thirdPartyUserId=" + idNum;
        return sendGet(parameter, type, accountsApi);
    }

    // 个人账号创建,businessContractorIdCard_c 设为模块对应id，只要保持唯一即可
    public static JSONObject createAccount(ESignParameter parameter, String type,
                                           String businessContractorIdCard_c,
                                           String agentName,
                                           String customer_phone_c) {

        JSONObject data = new JSONObject();
        data.put("thirdPartyUserId", businessContractorIdCard_c == null ? "" : businessContractorIdCard_c);
        data.put("name", agentName == null ? "" : agentName);
        //data.put("idType", "CRED_PSN_CH_IDCARD");
        //data.put("idNumber", businessContractorIdCard_c == null ? "" : businessContractorIdCard_c);
        data.put("mobile", customer_phone_c == null ? "" : customer_phone_c);
        //data.put("email", "");
        String accountsApi = "/v1/accounts/createByThirdPartyUserId";
        return sendPost(parameter, type, accountsApi, data);
    }

    // 个人账号注销- accountId
    public static JSONObject cancelAccountByAccountId(ESignParameter parameter, String type,
                                                    String accountId) {
        String accountsApi = "/v1/accounts/"+ accountId;
        return sendDelete(parameter, type, accountsApi, new JSONObject());
    }

    // 个人账号注销-身份证号
    public static JSONObject cancelAccountByThirdId(ESignParameter parameter, String type,
                                                    String thirdPartyUserId) {
        String accountsApi = "/v1/accounts/deleteByThirdId?thirdPartyUserId=" + thirdPartyUserId;
        return sendDelete(parameter, type, accountsApi, new JSONObject());
    }

    // 个人账号修改-accountId
    public static JSONObject updateAccountByID(ESignParameter parameter, String type, String accountId,
                                               String email, String mobile, String name) {
        String accountsApi = "/v1/accounts/" + accountId;
        JSONObject data = new JSONObject();
        data.put("email", email);
        data.put("mobile", mobile);
        data.put("name", name);
        return sendPut(parameter, type, accountsApi, data);
    }

    // 个人账号修改-身份证号
    public static JSONObject updateAccountByIDCard(ESignParameter parameter, String type, String accountId, String mobile) {
        String accountsApi = "/v1/accounts/updateByThirdId?thirdPartyUserId=" + accountId;
        JSONObject data = new JSONObject();
        data.put("mobile", mobile);
        return sendPost(parameter, type, accountsApi, data);
    }

    /***
     * 请求签名鉴权-PUT请求
     */
    public static JSONObject sendPut(ESignParameter parameter, String type, String accountsApi, JSONObject reqBodyObj) {

        JSONObject resultObj = new JSONObject();
        String appId = "";
        String appKey = "";
        String accountsApiUrl = "";
        if (type.equalsIgnoreCase("TEST")) {
            appId = parameter.getTestId();
            appKey = parameter.getTestKey();
            accountsApiUrl = parameter.getTestHost() + accountsApi;
        } else if (type.equalsIgnoreCase("PROD")) {
            appId = parameter.getProdId();
            appKey = parameter.getProdKey();
            accountsApiUrl = parameter.getProdHost() + accountsApi;
        }

        try {

            // 请求Body体数据
            String reqBodyData = reqBodyObj.toString();
            // 对请求Body体内的数据计算ContentMD5
            String contentMD5 = ESignEncryptionUtil.doContentMD5(reqBodyData);
            // 构建待签名字符串
            String method = "PUT";
            String accept = "*/*";
            String contentType = "application/json; charset=UTF-8";
            String url = accountsApi;
            String date = "";
            String headers = "";

            StringBuilder sb = new StringBuilder();
            sb.append(method).append("\n").append(accept).append("\n").append(contentMD5).append("\n")
                    .append(contentType).append("\n").append(date).append("\n");
            if ("".equals(headers)) {
                sb.append(headers).append(url);
            } else {
                sb.append(headers).append("\n").append(url);
            }

            // 构建参与请求签名计算的明文
            String plaintext = sb.toString();
            // 计算请求签名值
            String reqSignature = ESignEncryptionUtil.doSignatureBase64(plaintext, appKey);

            // 获取时间戳(精确到毫秒)
            long timeStamp = ESignEncryptionUtil.timeStamp();

            // 构建请求头
            LinkedHashMap<String, String> header = new LinkedHashMap<>();
            header.put("X-Tsign-Open-App-Id", appId);
            header.put("X-Tsign-Open-Auth-Mode", "Signature");
            header.put("X-Tsign-Open-Ca-Timestamp", String.valueOf(timeStamp));
            header.put("Accept", accept);
            header.put("Content-Type", contentType);
            header.put("X-Tsign-Open-Ca-Signature", reqSignature);
            header.put("Content-MD5", contentMD5);

            // 发送PUT请求
            String result = HTTPHelper.sendPUT(accountsApiUrl, reqBodyData, header, "UTF-8");
            resultObj = JSONObject.parseObject(result);
        } catch (Exception e) {
            e.printStackTrace();
            String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
            System.out.println(msg);
        }

        return resultObj;
    }

    /***
     * 请求签名鉴权-DELETE请求
     */
    public static JSONObject sendDelete(ESignParameter parameter, String type, String accountsApi, JSONObject reqBodyObj) {

        JSONObject resultObj = new JSONObject();
        String appId = "";
        String appKey = "";
        String accountsApiUrl = "";
        if (type.equalsIgnoreCase("TEST")) {
            appId = parameter.getTestId();
            appKey = parameter.getTestKey();
            accountsApiUrl = parameter.getTestHost() + accountsApi;
        } else if (type.equalsIgnoreCase("PROD")) {
            appId = parameter.getProdId();
            appKey = parameter.getProdKey();
            accountsApiUrl = parameter.getProdHost() + accountsApi;
        }

        try {

            // 请求Body体数据
            String reqBodyData = reqBodyObj.toString();
            // 对请求Body体内的数据计算ContentMD5
            String contentMD5 = ESignEncryptionUtil.doContentMD5(reqBodyData);
            // 构建待签名字符串
            String method = "DELETE";
            String accept = "*/*";
            String contentType = "application/json; charset=UTF-8";
            String url = accountsApi;
            String date = "";
            String headers = "";

            StringBuilder sb = new StringBuilder();
            sb.append(method).append("\n").append(accept).append("\n").append(contentMD5).append("\n")
                    .append(contentType).append("\n").append(date).append("\n");
            if ("".equals(headers)) {
                sb.append(headers).append(url);
            } else {
                sb.append(headers).append("\n").append(url);
            }

            // 构建参与请求签名计算的明文
            String plaintext = sb.toString();
            // 计算请求签名值
            String reqSignature = ESignEncryptionUtil.doSignatureBase64(plaintext, appKey);

            // 获取时间戳(精确到毫秒)
            long timeStamp = ESignEncryptionUtil.timeStamp();

            // 构建请求头
            LinkedHashMap<String, String> header = new LinkedHashMap<>();
            header.put("X-Tsign-Open-App-Id", appId);
            header.put("X-Tsign-Open-Auth-Mode", "Signature");
            header.put("X-Tsign-Open-Ca-Timestamp", String.valueOf(timeStamp));
            header.put("Accept", accept);
            header.put("Content-Type", contentType);
            header.put("X-Tsign-Open-Ca-Signature", reqSignature);
            header.put("Content-MD5", contentMD5);

            // 发送DELETE请求
            String result = HTTPHelper.sendDELETE(accountsApiUrl, reqBodyData, header, "UTF-8");
            resultObj = JSONObject.parseObject(result);
        } catch (Exception e) {
            e.printStackTrace();
            String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
            System.out.println(msg);
        }

        return resultObj;
    }

    /***
     * 请求签名鉴权-POST请求
     */
    public static JSONObject sendPost(ESignParameter parameter, String type, String accountsApi, JSONObject reqBodyObj) {

        JSONObject resultObj = new JSONObject();
        String appId = "";
        String appKey = "";
        String accountsApiUrl = "";
        if (type.equalsIgnoreCase("TEST")) {
            appId = parameter.getTestId();
            appKey = parameter.getTestKey();
            accountsApiUrl = parameter.getTestHost() + accountsApi;
        } else if (type.equalsIgnoreCase("PROD")) {
            appId = parameter.getProdId();
            appKey = parameter.getProdKey();
            accountsApiUrl = parameter.getProdHost() + accountsApi;
        }

        try {

            // 请求Body体数据
            String reqBodyData = reqBodyObj.toString();
            // 对请求Body体内的数据计算ContentMD5
            String contentMD5 = ESignEncryptionUtil.doContentMD5(reqBodyData);
            // 构建待签名字符串
            String method = "POST";
            String accept = "*/*";
            String contentType = "application/json; charset=UTF-8";
            String url = accountsApi;
            String date = "";
            String headers = "";

            StringBuilder sb = new StringBuilder();
            sb.append(method).append("\n").append(accept).append("\n").append(contentMD5).append("\n")
                    .append(contentType).append("\n").append(date).append("\n");
            if ("".equals(headers)) {
                sb.append(headers).append(url);
            } else {
                sb.append(headers).append("\n").append(url);
            }

            // 构建参与请求签名计算的明文
            String plaintext = sb.toString();
            // 计算请求签名值
            String reqSignature = ESignEncryptionUtil.doSignatureBase64(plaintext, appKey);

            // 获取时间戳(精确到毫秒)
            long timeStamp = ESignEncryptionUtil.timeStamp();

            // 构建请求头
            LinkedHashMap<String, String> header = new LinkedHashMap<>();
            header.put("X-Tsign-Open-App-Id", appId);
            header.put("X-Tsign-Open-Auth-Mode", "Signature");
            header.put("X-Tsign-Open-Ca-Timestamp", String.valueOf(timeStamp));
            header.put("Accept", accept);
            header.put("Content-Type", contentType);
            header.put("X-Tsign-Open-Ca-Signature", reqSignature);
            header.put("Content-MD5", contentMD5);

            // 发送POST请求
            String result = HTTPHelper.sendPOST(accountsApiUrl, reqBodyData, header, "UTF-8");
            resultObj = JSONObject.parseObject(result);
        } catch (Exception e) {
            e.printStackTrace();
            String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
            System.out.println(msg);
        }

        return resultObj;
    }

    /***
     * 请求签名鉴权-GET请求
     */
    public static JSONObject sendGet(ESignParameter parameter, String type, String accountsApi) {

        JSONObject resultObj = new JSONObject();
        String appId = "";
        String appKey = "";
        String hostGetSignFlowApi = "";
        if (type.equalsIgnoreCase("TEST")) {
            appId = parameter.getTestId();
            appKey = parameter.getTestKey();
            hostGetSignFlowApi = parameter.getTestHost() + accountsApi;
        } else if (type.equalsIgnoreCase("PROD")) {
            appId = parameter.getProdId();
            appKey = parameter.getProdKey();
            hostGetSignFlowApi = parameter.getProdHost() + accountsApi;
        }

        try {
            // GET请求时ContentMD5为""
            String contentMD5 = "";

            // 构建待签名字符串
            String method = "GET";
            String accept = "*/*";
            String contentType = "application/json; charset=UTF-8";
            String url = accountsApi;
            String date = "";
            String headers = "";

            StringBuffer sb = new StringBuffer();
            sb.append(method).append("\n").append(accept).append("\n").append(contentMD5).append("\n")
                    .append(contentType).append("\n").append(date).append("\n");
            if ("".equals(headers)) {
                sb.append(headers).append(url);
            } else {
                sb.append(headers).append("\n").append(url);
            }

            // 构建参与请求签名计算的明文
            String plaintext = sb.toString();
            // 计算请求签名值
            String reqSignature = ESignEncryptionUtil.doSignatureBase64(plaintext, appKey);

            // 获取时间戳(精确到毫秒)
            long timeStamp = ESignEncryptionUtil.timeStamp();

            // 构建请求头
            LinkedHashMap<String, String> header = new LinkedHashMap<>();
            header.put("X-Tsign-Open-App-Id", appId);
            header.put("X-Tsign-Open-Auth-Mode", "Signature");
            header.put("X-Tsign-Open-Ca-Timestamp", String.valueOf(timeStamp));
            header.put("Accept", accept);
            header.put("Content-Type", contentType);
            header.put("X-Tsign-Open-Ca-Signature", reqSignature);
            header.put("Content-MD5", contentMD5);

            // 发送GET请求
            String result = HTTPHelper.sendGet(hostGetSignFlowApi, header, "UTF-8");
            resultObj = JSONObject.parseObject(result);
        } catch (Exception e) {
            e.printStackTrace();
            String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
            System.out.println(msg);
        }

        return resultObj;
    }

    /***
     * 请求签名鉴权-GET请求
     */
    public static JSONObject sendGetForPosition(ESignParameter parameter, String type, String accountsApi, String keyWord) {

        JSONObject resultObj = new JSONObject();
        String appId = "";
        String appKey = "";
        String hostGetSignFlowApi = "";
        if (type.equalsIgnoreCase("TEST")) {
            appId = parameter.getTestId();
            appKey = parameter.getTestKey();
            hostGetSignFlowApi = parameter.getTestHost() + accountsApi;
        } else if (type.equalsIgnoreCase("PROD")) {
            appId = parameter.getProdId();
            appKey = parameter.getProdKey();
            hostGetSignFlowApi = parameter.getProdHost() + accountsApi;
        }

        try {
            // GET请求时ContentMD5为""
            String contentMD5 = "";

            // 构建待签名字符串
            String method = "GET";
            String accept = "*/*";
            String contentType = "application/json; charset=UTF-8";
            String url = accountsApi;
            String date = "";
            String headers = "";

            StringBuffer sb = new StringBuffer();
            sb.append(method).append("\n").append(accept).append("\n").append(contentMD5).append("\n")
                    .append(contentType).append("\n").append(date).append("\n");
            if ("".equals(headers)) {
                sb.append(headers).append(url);
            } else {
                sb.append(headers).append("\n").append(url);
            }

            // 构建参与请求签名计算的明文
            String plaintext = sb.toString();
            // 计算请求签名值
            String reqSignature = ESignEncryptionUtil.doSignatureBase64(plaintext, appKey);
            // 获取时间戳(精确到毫秒)
            long timeStamp = ESignEncryptionUtil.timeStamp();

            // 构建请求头
            LinkedHashMap<String, String> header = new LinkedHashMap<>();
            header.put("X-Tsign-Open-App-Id", appId);
            header.put("X-Tsign-Open-Auth-Mode", "Signature");
            header.put("X-Tsign-Open-Ca-Timestamp", String.valueOf(timeStamp));
            header.put("Accept", accept);
            header.put("Content-Type", contentType);
            header.put("X-Tsign-Open-Ca-Signature", reqSignature);
            header.put("Content-MD5", contentMD5);

            // 发送GET请求
            try {
                /**
                 * 注：计算plaintext时，中文不编码
                 * 在请求时，要把中文编码
                 */
                hostGetSignFlowApi = hostGetSignFlowApi.substring(0, hostGetSignFlowApi.indexOf("keywords=") + "keywords=".length());
                hostGetSignFlowApi += URLEncoder.encode(keyWord, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            String result = HTTPHelper.sendGet(hostGetSignFlowApi, header, "UTF-8");
            resultObj = JSONObject.parseObject(result);
        } catch (Exception e) {
            e.printStackTrace();
            String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
            System.out.println(msg);
        }

        return resultObj;
    }

    /***
     * 请求签名鉴权-PUT请求
     */
    //public static JSONObject sendPut(String uploadUrl, String fileContentMd5, String filePath, String contentType) {
    //    HttpHeaders headers = new HttpHeaders();
    //    headers.set("Content-MD5", fileContentMd5);
    //    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
    //    // 将请求头部和参数合成一个请求
    //    HttpEntity<byte[]> requestEntity = null;
    //    try {
    //        requestEntity = new HttpEntity<>(IOUtils.toByteArray(new FileInputStream(filePath)), headers);
    //    } catch (Exception e) {
    //        e.printStackTrace();
    //    }
    //
    //    // 执行HTTP请求，将返回的结构使用JSONObject类格式化
    //    ResponseEntity<JSONObject> result = client.exchange(uploadUrl, HttpMethod.PUT, requestEntity, JSONObject.class);
    //    return result.getBody();
    //
    //}

    /**
     * 获取上传文件路径
     */
    public static JSONObject getUploadFileUrl(ESignParameter parameter, String type, JSONObject data) {

        String accountsApi = "/v1/files/getUploadUrl";
        return sendPost(parameter, type, accountsApi, data);
    }

    /**
     * 文件流上传
     *
     * @return
     */
    public static EsignHttpResponse uploadFile(String uploadUrl, String filePath) {
        //根据文件地址获取文件contentMd5
        EsignFileBean esignFileBean = null;
        try {
            esignFileBean = new EsignFileBean(filePath);
        } catch (EsignDemoException e) {
            e.printStackTrace();
        }
        //请求方法
        EsignRequestType requestType = EsignRequestType.PUT;
        try {
            return EsignHttpHelper.doUploadHttp(uploadUrl, requestType, esignFileBean.getFileBytes(), esignFileBean.getFileContentMD5(), EsignHeaderConstant.CONTENTTYPE_STREAM.VALUE(), true);
        } catch (EsignDemoException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 查询文件上传状态
     */
    public static JSONObject getFileUploadStatus(ESignParameter parameter, String type, String fileId) {
        String accountsApi = "/v1/files/" + fileId + "/status";
        return sendGet(parameter, type, accountsApi);
    }

    /**
     * 搜索关键字坐标
     */
    public static JSONObject getKeyWordPosition(ESignParameter parameter, String type, String fileId, String keyWord) {
        String accountsApi = "/v1/documents/" + fileId + "/searchWordsPosition?keywords=" + keyWord;
        return sendGetForPosition(parameter, type, accountsApi, keyWord);
    }

    /**
     * 查询PDF文件详情
     */
    public static JSONObject getPDF(ESignParameter parameter, String type, String fileId) {
        String accountsApi = "/v1/files/" + fileId;
        return sendGet(parameter, type, accountsApi);
    }

    /**
     * 一步发起签署
     */
    public static JSONObject launchESign(ESignParameter parameter, String type, JSONObject data) {
        String accountsApi = "/api/v2/signflows/createFlowOneStep";
        return sendPost(parameter, type, accountsApi, data);
    }

    /**
     * 流程文档下载
     */
    public static JSONObject downloadFile(ESignParameter parameter, String type, String flowId) {
        String accountsApi = "/v1/signflows/" + flowId + "/documents";
        return sendGet(parameter, type, accountsApi);
    }
}
